﻿using System;
using System.Net;
using System.Threading;
using Lextm.SharpSnmpLib.Messaging;

namespace SNMS.Manager.Infrastructure
{
    // Usage:
    // TrapNotificationListener tnl = new TrapNotificationListener(new IPEndPoint(IPAddress.Any,162));
    // tnl.Trap1Recived += (o, e) => {
    //     Console.WriteLine(e.Message.ToString());
    // };
    // tnl.Trap2Recived += (o, e) => {
    //     Console.WriteLine(e.Message.ToString());
    // };
    // tnl.InformRecived += (o, e) => {
    //     Console.WriteLine(e.Message.ToString());
    // };
    // tnl.TrapNotificationError += (o, e) => {
    //     Console.WriteLine(e.Exception.Message);
    // };
    // tnl.Start();
    // Console.ReadLine();
    public class TrapNotificationListener
    {
        private Listener listener;
        private ManagerV1ListenerAdapter trap1;
        private ManagerV2ListenerAdapter trap2;
        private ManagerV3ListenerAdapter trap2AndInform;

        public TrapNotificationListener(IPEndPoint endpoint) {
            listener = new Listener();
            trap1 = new ManagerV1ListenerAdapter();
            trap2 = new ManagerV2ListenerAdapter();
            trap2AndInform = new ManagerV3ListenerAdapter();
            listener.Adapters.Add(trap1);
            listener.Adapters.Add(trap2);
            listener.Adapters.Add(trap2AndInform);
            RegisterEvent();
            listener.AddBinding(endpoint);
        }

        private void RegisterEvent()
        {
            trap1.TrapV1Received += (o, e) => {
                OnTrap1Recived(e);
            };
            trap2.TrapV2Received += (o, e) => {
                OnTrap2Recived(e);
            };
            trap2.InformRequestReceived += (o, e) => {
                OnInformRecived(e);
            };
            trap2AndInform.TrapV2Received += (o, e) => {
                OnTrap2Recived(e);
            };
            trap2AndInform.InformRequestReceived += (o, e) => {
                OnInformRecived(e);
            };
        }

        public void Start() {
            try
            {
                listener.Start();
            }
            catch (Exception e) {
                OnTrapNotificaionError(new TrapNotificationErrorArgs { Exception = e});
            }
        }

        public void Stop() {
            try{
                listener.Stop();
            }catch (Exception e) {
                OnTrapNotificaionError(new TrapNotificationErrorArgs { Exception = e });
            }
        }

        #region Events

        public event EventHandler<MessageReceivedEventArgs<TrapV1Message>> Trap1Recived;
        protected virtual void OnTrap1Recived(MessageReceivedEventArgs<TrapV1Message> e)
        {
            var handle = Interlocked.CompareExchange(ref Trap1Recived, null, null);
            if (handle != null)
            {
                handle(this, e);
            }
        }

        public event EventHandler<MessageReceivedEventArgs<TrapV2Message>> Trap2Recived;
        protected virtual void OnTrap2Recived(MessageReceivedEventArgs<TrapV2Message> e)
        {
            var handle = Interlocked.CompareExchange(ref Trap2Recived, null, null);
            if (handle != null)
            {
                handle(this, e);
            }
        }

        public event EventHandler<MessageReceivedEventArgs<InformRequestMessage>> InformRecived;
        protected virtual void OnInformRecived(MessageReceivedEventArgs<InformRequestMessage> e)
        {
            var handle = Interlocked.CompareExchange(ref InformRecived, null, null);
            if (handle != null)
            {
                handle(this, e);
            }
        }

        public event EventHandler<TrapNotificationErrorArgs> TrapNotificationError;
        protected virtual void OnTrapNotificaionError(TrapNotificationErrorArgs e)
        {
            var handle = Interlocked.CompareExchange(ref TrapNotificationError, null, null);
            if (handle != null)
            {
                handle(this, e);
            }
        }
        #endregion
    }

    public sealed class TrapNotificationErrorArgs : EventArgs {
        public Exception Exception { get; set; }
    }
}
